﻿using Joy.Erp.BasicArchives.Core.EntityAttributes;
using Joy.Erp.BasicArchives.Localization;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Domain.Entities;

namespace Joy.Erp.BasicArchives.Core
{
    public static class UniqueAttributeExtensions
    {
        public static async Task CheckUniquePropertyAsync<TEntity, TKey>(this IQueryable<TEntity> queryable, TEntity entity)
            where TEntity : class, IEntity<TKey>, IArchiveAggregateRoot<TKey>
        {
            foreach (var propertyInfo in typeof(TEntity).GetProperties())
            {
                if (propertyInfo.GetCustomAttribute(typeof(UniqueAttribute), false) != null)
                {
                    var parameter = Expression.Parameter(typeof(TEntity), "entity");
                    var property = typeof(TEntity).GetProperty(propertyInfo.Name);

                    // 创建属性访问表达式 entity.PropertyName
                    var propertyAccess = Expression.Property(parameter, property);

                    // 创建常量表达式 propertyValue
                    var constant = Expression.Constant(propertyInfo.GetValue(entity));

                    // 创建等于运算表达式 entity.PropertyName == propertyValue
                    var equals = Expression.Equal(propertyAccess, constant);

                    // 创建lambda表达式 entity => entity.PropertyName == propertyValue
                    var predicate = Expression.Lambda<Func<TEntity, bool>>(equals, parameter);

                    var count = await queryable
                            .Where(predicate)
                            .Where(x => !x.Id.Equals(entity.Id))
                            .LongCountAsync();
                    if (count > 0)
                    {
                        var resourceKey = $"ModelDesc:{propertyInfo.ReflectedType.Namespace}.{propertyInfo.ReflectedType.Name}.{propertyInfo.Name}";
                        throw new BusinessException("BasicArchives:001").WithData("PropertyName", resourceKey).WithData("PropertyValue", propertyInfo.GetValue(entity));
                    }
                }
            }
        }

        public static async Task CheckUniquePropertyAsync<TEntity>(this IQueryable<TEntity> queryable, TEntity entity)
            where TEntity : class, IEntity, IArchiveAggregateRoot
        {
            await queryable.CheckUniquePropertyAsync<TEntity, Guid>(entity);
        }
    }
}
